commonlibsse_ng\re\m\Misc/
message_box.rs

1use core::ffi::{CStr, c_char};
2use core::ptr;
3
4use crate::re::GameSettingCollection::GameSettingCollection;
5use crate::re::IMessageBoxCallback::{IMessageBoxCallback, Message};
6use crate::re::Setting::SettingValue;
7
8#[commonlibsse_ng_derive_internal::relocate_fn(se_id = 51420, ae_id = 52269)]
9pub fn CreateMessage(
10    message: *const c_char,
11    callback: *mut IMessageBoxCallback,
12    arg3: u32,
13    arg4: u32,
14    arg5: u32,
15    button_text: *const c_char,
16    secondary_button_text: *const c_char,
17) {
18}
19
20/// The configuration for displaying the message box.
21pub struct MessageBoxConfig<'a> {
22    /// The message to be displayed in the message box.
23    pub message: &'a CStr,
24    /// Text for the primary button (defaults to `"OK"`)
25    ///
26    /// If a task is registered, press this button in the game to execute it.
27    pub button_text: &'a CStr,
28    /// Text for the secondary button (no secondary button if None)
29    pub secondary_button_text: Option<&'a CStr>,
30    /// Optional task (closure) to execute when a button is pressed
31    ///
32    /// FIXME: Currently not running as it crashes mysteriously.
33    pub task: Option<fn(Message)>,
34}
35
36impl Default for MessageBoxConfig<'_> {
37    fn default() -> Self {
38        Self {
39            message: c"",
40            button_text: c"OK",
41            secondary_button_text: None,
42            task: Default::default(),
43        }
44    }
45}
46
47/// Displays a message box with the given configuration.
48///
49/// This function creates a message box with the provided `message` and optional button texts.
50/// If a `task` is provided, it will be executed when the button is pressed.
51///
52/// # Example
53/// ```no_run
54/// use std::ffi::CString;
55/// use commonlibsse_ng::re::Misc::{DebugMessageBoxWithConfig, MessageBoxConfig};
56///
57/// let message = CString::new(format!("This is a {}", "message")).unwrap();
58///
59/// let config = MessageBoxConfig {
60///     message: &message,
61///     button_text: c"Yes",
62///     secondary_button_text: Some(c"No"),
63///     task: None,
64/// };
65///
66/// DebugMessageBoxWithConfig(config);
67/// ```
68///
69/// # Message Box Layout
70/// ```txt
71/// +--------------------------+
72/// |    This is a message     |
73/// |                          |
74/// |     [Yes]     [No]       |  <-- Primary and Secondary Buttons
75/// +--------------------------+
76/// ```
77#[inline]
78pub fn DebugMessageBoxWithConfig(config: MessageBoxConfig) {
79    // If secondary button text is not provided, use null pointer
80    let secondary_button_text =
81        config.secondary_button_text.map_or(ptr::null(), |cstr| cstr.as_ptr());
82
83    // FIXME: Currently not running as it crashes mysteriously.
84    // If a task is provided, create a callback for it
85    // use crate::re::OldMessageBoxCallback::OldMessageBoxCallback;
86    // let callback_ptr = config
87    //     .task
88    //     .map_or(ptr::null_mut(), |task| Box::into_raw(Box::new(OldMessageBoxCallback::new(task))));
89
90    CreateMessage(
91        config.message.as_ptr(),
92        // callback_ptr.cast(),
93        ptr::null_mut(),
94        0,
95        4,
96        10,
97        config.button_text.as_ptr(),
98        secondary_button_text,
99    );
100    // drop(unsafe { Box::from_raw(callback_ptr) });
101}
102
103/// Display a simple dialog box with the given message.
104///
105/// # Message Box Layout
106/// ```txt
107/// +--------------------------+
108/// |    This is a message     |
109/// |                          |
110/// |          [OK]            |  <-- Primary Buttons
111/// +--------------------------+
112/// ```
113///
114/// # Example
115/// ```no_run
116/// commonlibsse_ng::re::Misc::DebugMessageBox(c"This is a message");
117/// ```
118#[inline]
119pub fn DebugMessageBox(message: &CStr) {
120    DebugMessageBoxWithConfig(MessageBoxConfig { message, ..Default::default() });
121}
122
123/// C++ `DebugMessageBox`
124///
125/// with i18n `OK` button
126pub fn DebugMessageOkBox(message: &CStr) {
127    unsafe {
128        let ok_button = GameSettingCollection::get_singleton()
129            .and_then(|gsc| gsc.__base.settings.__base.__base.__base.get(&c"sOk".as_ptr()))
130            .and_then(|setting| {
131                if let SettingValue::String(string) = setting.as_ref()?.get_value() {
132                    return Some(string);
133                }
134                None
135            })
136            .unwrap_or(c"OK");
137        DebugMessageBoxWithConfig(MessageBoxConfig {
138            message,
139            button_text: ok_button,
140            ..Default::default()
141        });
142    }
143}